<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name=Generator content="Microsoft Word 14 (filtered)">

<style>
<!--
 /* Font Definitions */
 @font-face
	{font-family:Wingdings;
	panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
	{font-family:宋体;
	panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
	{font-family:黑体;
	panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
	{font-family:黑体;
	panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
	{font-family:方正小标宋简体;}
@font-face
	{font-family:"\@黑体";
	panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
	{font-family:"\@宋体";
	panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
	{font-family:"\@方正小标宋简体";}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
h1
	{mso-style-link:"标题 1 Char";
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:7.2pt;
	text-align:center;
	text-indent:-7.2pt;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
h2
	{mso-style-link:"标题 2 Char";
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:0cm;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:0cm;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
h3
	{mso-style-link:"标题 3 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:0cm;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
h4
	{mso-style-link:"标题 4 Char";
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:28.8pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-28.8pt;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
h5
	{mso-style-link:"标题 5 Char";
	margin-top:14.0pt;
	margin-right:0cm;
	margin-bottom:14.5pt;
	margin-left:36.0pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-36.0pt;
	line-height:156%;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:宋体;
	font-weight:bold;}
h6
	{mso-style-link:"标题 6 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:43.2pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-43.2pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.MsoHeading7, li.MsoHeading7, div.MsoHeading7
	{mso-style-link:"标题 7 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:50.4pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-50.4pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:宋体;
	font-weight:bold;}
p.MsoHeading8, li.MsoHeading8, div.MsoHeading8
	{mso-style-link:"标题 8 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:57.6pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-72.0pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";}
p.MsoHeading9, li.MsoHeading9, div.MsoHeading9
	{mso-style-link:"标题 9 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:64.8pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-79.2pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.MsoIndex1, li.MsoIndex1, div.MsoIndex1
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:10.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex2, li.MsoIndex2, div.MsoIndex2
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex3, li.MsoIndex3, div.MsoIndex3
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:31.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex4, li.MsoIndex4, div.MsoIndex4
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex5, li.MsoIndex5, div.MsoIndex5
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:52.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex6, li.MsoIndex6, div.MsoIndex6
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:63.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex7, li.MsoIndex7, div.MsoIndex7
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:73.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex8, li.MsoIndex8, div.MsoIndex8
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:84.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex9, li.MsoIndex9, div.MsoIndex9
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:94.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoToc1, li.MsoToc1, div.MsoToc1
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;
	font-weight:bold;}
p.MsoToc2, li.MsoToc2, div.MsoToc2
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoToc3, li.MsoToc3, div.MsoToc3
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoToc4, li.MsoToc4, div.MsoToc4
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:31.5pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc5, li.MsoToc5, div.MsoToc5
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc6, li.MsoToc6, div.MsoToc6
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:52.5pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc7, li.MsoToc7, div.MsoToc7
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:63.0pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc8, li.MsoToc8, div.MsoToc8
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:73.5pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc9, li.MsoToc9, div.MsoToc9
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:84.0pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoFootnoteText, li.MsoFootnoteText, div.MsoFootnoteText
	{mso-style-link:"脚注文本 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoCommentText, li.MsoCommentText, div.MsoCommentText
	{mso-style-link:"批注文字 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoHeader, li.MsoHeader, div.MsoHeader
	{mso-style-link:"页眉 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	layout-grid-mode:char;
	border:none;
	padding:0cm;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoFooter, li.MsoFooter, div.MsoFooter
	{mso-style-link:"页脚 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoIndexHeading, li.MsoIndexHeading, div.MsoIndexHeading
	{mso-style-name:"索引标题\,索引类目\,索引类目1\,索引类目2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoCaption, li.MsoCaption, div.MsoCaption
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.MsoTof, li.MsoTof, div.MsoTof
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
span.MsoFootnoteReference
	{vertical-align:super;}
p.MsoList, li.MsoList, div.MsoList
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoList2, li.MsoList2, div.MsoList2
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoList4, li.MsoList4, div.MsoList4
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoDate, li.MsoDate, div.MsoDate
	{mso-style-link:"日期 Char";
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:5.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
a:link, span.MsoHyperlink
	{mso-style-name:"超链接\,超级链接";
	color:blue;
	text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
	{color:purple;
	text-decoration:underline;}
p
	{mso-style-name:"普通\(网站\)\,普通 \(Web\)\,普通 \(Web\)1\,普通 \(Web\)2\,普通 \(Web\)3";
	margin-right:0cm;
	margin-left:0cm;
	font-size:12.0pt;
	font-family:宋体;}
pre
	{mso-style-name:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3";
	mso-style-link:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:12.0pt;
	font-family:宋体;}
tt
	{font-family:黑体;}
p.MsoCommentSubject, li.MsoCommentSubject, div.MsoCommentSubject
	{mso-style-link:"批注主题 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.5pt;
	font-family:宋体;
	font-weight:bold;}
p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
	{mso-style-link:"批注框文本 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:9.0pt;
	font-family:宋体;}
p.1, li.1, div.1
	{mso-style-name:样式1;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.a, li.a, div.a
	{mso-style-name:代码程序;
	mso-style-link:"代码程序 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
span.Char
	{mso-style-name:"代码程序 Char";
	mso-style-link:代码程序;
	font-family:宋体;}
p.a0, li.a0, div.a0
	{mso-style-name:图说明;
	mso-style-link:"图说明 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
span.Char0
	{mso-style-name:"图说明 Char";
	mso-style-link:图说明;
	font-family:宋体;}
p.0, li.0, div.0
	{mso-style-name:封面0;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.10, li.10, div.10
	{mso-style-name:封面1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.11, li.11, div.11
	{mso-style-name:非标题1;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.a1, li.a1, div.a1
	{mso-style-name:文本居中;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3CharChar, li.3CharChar, div.3CharChar
	{mso-style-name:"图中文字3 Char Char";
	mso-style-link:"图中文字3 Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
span.3CharCharChar
	{mso-style-name:"图中文字3 Char Char Char";
	mso-style-link:"图中文字3 Char Char";
	font-family:宋体;}
p.post, li.post, div.post
	{mso-style-name:邮件post;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.3, li.3, div.3
	{mso-style-name:图中字体3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.3CharChar1CharCharChar
	{mso-style-name:"图中文字3 Char Char1 Char Char Char";
	font-family:宋体;}
span.3CharChar1CharChar
	{mso-style-name:"图中文字3 Char Char1 Char Char";
	font-family:宋体;}
p.5Char, li.5Char, div.5Char
	{mso-style-name:"图中文字5号 Char";
	mso-style-link:"图中文字5号 Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
span.5CharChar
	{mso-style-name:"图中文字5号 Char Char";
	mso-style-link:"图中文字5号 Char";
	font-family:宋体;}
p.5CharChar0, li.5CharChar0, div.5CharChar0
	{mso-style-name:"图中文字小5号 Char Char";
	mso-style-link:"图中文字小5号 Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
span.5CharCharChar
	{mso-style-name:"图中文字小5号 Char Char Char";
	mso-style-link:"图中文字小5号 Char Char";
	font-family:宋体;}
p.5Char0, li.5Char0, div.5Char0
	{mso-style-name:"图中文字小5号 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.5, li.5, div.5
	{mso-style-name:图中文字小5号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.2, li.2, div.2
	{mso-style-name:代码程序2;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
p.20, li.20, div.20
	{mso-style-name:图说明2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.21, li.21, div.21
	{mso-style-name:文本居中2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3CharCharCharCharChar, li.3CharCharCharCharChar, div.3CharCharCharCharChar
	{mso-style-name:"图中文字3 Char Char Char Char Char";
	mso-style-link:"图中文字3 Char Char Char Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
span.3CharCharCharCharCharChar
	{mso-style-name:"图中文字3 Char Char Char Char Char Char";
	mso-style-link:"图中文字3 Char Char Char Char Char";
	font-family:宋体;}
p.a2, li.a2, div.a2
	{mso-style-name:图居中;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.110, li.110, div.110
	{mso-style-name:"样式 标题 1 + 居中1";
	margin-right:0cm;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
span.1Char
	{mso-style-name:"标题 1 Char";
	mso-style-link:"标题 1";
	font-weight:bold;}
p.22, li.22, div.22
	{mso-style-name:"样式 列表 2 + 居中";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.23, li.23, div.23
	{mso-style-name:列表2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.50, li.50, div.50
	{mso-style-name:图中文字5号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.111, li.111, div.111
	{mso-style-name:样式11;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.12, li.12, div.12
	{mso-style-name:代码程序1;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
p.13, li.13, div.13
	{mso-style-name:图说明1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.01, li.01, div.01
	{mso-style-name:封面01;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.112, li.112, div.112
	{mso-style-name:封面11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.113, li.113, div.113
	{mso-style-name:非标题11;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.14, li.14, div.14
	{mso-style-name:文本居中1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3Char1, li.3Char1, div.3Char1
	{mso-style-name:"图中文字3 Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.post1, li.post1, div.post1
	{mso-style-name:邮件post1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.31, li.31, div.31
	{mso-style-name:图中字体31;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.5Char1, li.5Char1, div.5Char1
	{mso-style-name:"图中文字5号 Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.5CharChar1, li.5CharChar1, div.5CharChar1
	{mso-style-name:"图中文字小5号 Char Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.5Char10, li.5Char10, div.5Char10
	{mso-style-name:"图中文字小5号 Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.51, li.51, div.51
	{mso-style-name:图中文字小5号1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.120, li.120, div.120
	{mso-style-name:样式12;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.02, li.02, div.02
	{mso-style-name:封面02;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.121, li.121, div.121
	{mso-style-name:封面12;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.122, li.122, div.122
	{mso-style-name:非标题12;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.3Char2, li.3Char2, div.3Char2
	{mso-style-name:"图中文字3 Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.post2, li.post2, div.post2
	{mso-style-name:邮件post2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.32, li.32, div.32
	{mso-style-name:图中字体32;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.5Char2, li.5Char2, div.5Char2
	{mso-style-name:"图中文字小5号 Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.52, li.52, div.52
	{mso-style-name:图中文字小5号2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.3CharCharCharChar, li.3CharCharCharChar, div.3CharCharCharChar
	{mso-style-name:"图中文字3 Char Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.130, li.130, div.130
	{mso-style-name:样式13;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.30, li.30, div.30
	{mso-style-name:代码程序3;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
p.03, li.03, div.03
	{mso-style-name:封面03;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.131, li.131, div.131
	{mso-style-name:封面13;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.132, li.132, div.132
	{mso-style-name:非标题13;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.33, li.33, div.33
	{mso-style-name:文本居中3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3Char3, li.3Char3, div.3Char3
	{mso-style-name:"图中文字3 Char3";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.post3, li.post3, div.post3
	{mso-style-name:邮件post3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.330, li.330, div.330
	{mso-style-name:图中字体33;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.5Char20, li.5Char20, div.5Char20
	{mso-style-name:"图中文字5号 Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.5CharChar2, li.5CharChar2, div.5CharChar2
	{mso-style-name:"图中文字小5号 Char Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.5Char3, li.5Char3, div.5Char3
	{mso-style-name:"图中文字小5号 Char3";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.53, li.53, div.53
	{mso-style-name:图中文字小5号3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.3Char, li.3Char, div.3Char
	{mso-style-name:"图中文字3 Char";
	mso-style-link:"图中文字3 Char Char5";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
span.3CharChar5
	{mso-style-name:"图中文字3 Char Char5";
	mso-style-link:"图中文字3 Char";
	font-family:宋体;}
p.54, li.54, div.54
	{mso-style-name:图中文字小5紧密;
	margin:0cm;
	margin-bottom:.0001pt;
	line-height:9.0pt;
	text-autospace:ideograph-numeric;
	font-size:9.0pt;
	font-family:宋体;}
p.24, li.24, div.24
	{mso-style-name:居中2号粗宋体;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.15, li.15, div.15
	{mso-style-name:"样式 标题 1 + 居中";
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.25, li.25, div.25
	{mso-style-name:"样式 标题 2 + 行距\: 单倍行距";
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:28.9pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-28.9pt;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.2Char
	{mso-style-name:"标题 2 Char";
	mso-style-link:"标题 2";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.34, li.34, div.34
	{mso-style-name:列表3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.35, li.35, div.35
	{mso-style-name:表3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.4, li.4, div.4
	{mso-style-name:图说明4;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.40, li.40, div.40
	{mso-style-name:列表4;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.41, li.41, div.41
	{mso-style-name:表4;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.55, li.55, div.55
	{mso-style-name:图说明5;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.56, li.56, div.56
	{mso-style-name:列表5;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.57, li.57, div.57
	{mso-style-name:表5;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.6, li.6, div.6
	{mso-style-name:列表6;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.60, li.60, div.60
	{mso-style-name:表6;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.61, li.61, div.61
	{mso-style-name:图说明6;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.7, li.7, div.7
	{mso-style-name:列表7;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.70, li.70, div.70
	{mso-style-name:图说明7;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.71, li.71, div.71
	{mso-style-name:表7;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.8, li.8, div.8
	{mso-style-name:列表8;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.9, li.9, div.9
	{mso-style-name:列表9;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.90, li.90, div.90
	{mso-style-name:图说明9;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.100, li.100, div.100
	{mso-style-name:列表10;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.101, li.101, div.101
	{mso-style-name:图说明10;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.114, li.114, div.114
	{mso-style-name:列表11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.115, li.115, div.115
	{mso-style-name:图说明11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.116, li.116, div.116
	{mso-style-name:表11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.123, li.123, div.123
	{mso-style-name:列表12;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.124, li.124, div.124
	{mso-style-name:图说明12;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.133, li.133, div.133
	{mso-style-name:图说明13;
	mso-style-link:"图说明13 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
span.13Char
	{mso-style-name:"图说明13 Char";
	mso-style-link:图说明13;
	font-family:宋体;}
p.134, li.134, div.134
	{mso-style-name:列表13;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.26, li.26, div.26
	{mso-style-name:附录2;
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:0cm;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.36, li.36, div.36
	{mso-style-name:附录3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.3Char0
	{mso-style-name:"标题 3 Char";
	mso-style-link:"标题 3";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.16, li.16, div.16
	{mso-style-name:附录1;
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.17, li.17, div.17
	{mso-style-name:附录表1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.42, li.42, div.42
	{mso-style-name:附录4;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.4Char
	{mso-style-name:"标题 4 Char";
	mso-style-link:"标题 4";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.a3, li.a3, div.a3
	{mso-style-name:附录图说明;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.27, li.27, div.27
	{mso-style-name:序标题2;
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:28.8pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-28.8pt;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.a4, li.a4, div.a4
	{mso-style-name:参考标题;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.18, li.18, div.18
	{mso-style-name:索引标题1;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.19, li.19, div.19
	{mso-style-name:列表1;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
p.1a, li.1a, div.1a
	{mso-style-name:表1;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
p.37, li.37, div.37
	{mso-style-name:图说明3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.62, li.62, div.62
	{mso-style-name:表中字体6号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	layout-grid-mode:char;
	font-size:7.5pt;
	font-family:宋体;}
p.a5, li.a5, div.a5
	{mso-style-name:正文代码;
	mso-style-link:"正文代码 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char1
	{mso-style-name:"正文代码 Char";
	mso-style-link:正文代码;
	font-family:宋体;}
p.43, li.43, div.43
	{mso-style-name:"样式 标题 4 +";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.140, li.140, div.140
	{mso-style-name:表14;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
p.141, li.141, div.141
	{mso-style-name:图说明14;
	mso-style-link:"图说明14 Char";
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
span.14Char
	{mso-style-name:"图说明14 Char";
	mso-style-link:图说明14;
	font-family:宋体;}
p.a6, li.a6, div.a6
	{mso-style-name:文件目录表;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.a7, li.a7, div.a7
	{mso-style-name:"样式 正文 +";
	mso-style-link:"样式 正文 + Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char2
	{mso-style-name:"样式 正文 + Char";
	mso-style-link:"样式 正文 +";
	font-family:"Times New Roman","serif";}
p.a8, li.a8, div.a8
	{mso-style-name:表格题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.a9, li.a9, div.a9
	{mso-style-name:列表题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.aa, li.aa, div.aa
	{mso-style-name:图题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.ab, li.ab, div.ab
	{mso-style-name:程序题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.ac, li.ac, div.ac
	{mso-style-name:框中文字;
	margin-top:0cm;
	margin-right:21.0pt;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	border:none;
	padding:0cm;
	font-size:9.0pt;
	font-family:宋体;}
p.125, li.125, div.125
	{mso-style-name:"样式 标题 1 + 居中2";
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.ad, li.ad, div.ad
	{mso-style-name:"样式 题注 + 宋体 五号 居中";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:黑体;}
p.1b, li.1b, div.1b
	{mso-style-name:序标题1;
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	line-height:240%;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:宋体;
	font-weight:bold;}
p.38, li.38, div.38
	{mso-style-name:序标题3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:方正小标宋简体;}
p.63, li.63, div.63
	{mso-style-name:表中文字6号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:7.5pt;
	font-family:宋体;}
p.64, li.64, div.64
	{mso-style-name:图中文字6号左对齐;
	margin:0cm;
	margin-bottom:.0001pt;
	line-height:10.0pt;
	layout-grid-mode:char;
	font-size:7.5pt;
	font-family:宋体;}
p.65, li.65, div.65
	{mso-style-name:图中文字6号;
	mso-style-link:"图中文字6号 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:10.0pt;
	layout-grid-mode:char;
	font-size:7.5pt;
	font-family:宋体;}
span.6Char
	{mso-style-name:"图中文字6号 Char";
	mso-style-link:图中文字6号;
	font-family:宋体;}
p.ae, li.ae, div.ae
	{mso-style-name:图标;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.28, li.28, div.28
	{mso-style-name:图标2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.af, li.af, div.af
	{mso-style-name:习题标题;
	margin-top:6.0pt;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:黑体;}
p.1c, li.1c, div.1c
	{mso-style-name:部分编号1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:16.0pt;
	font-family:宋体;}
p.af0, li.af0, div.af0
	{mso-style-name:表标题;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.af1, li.af1, div.af1
	{mso-style-name:"样式 题注 + 居中";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.ListTitle, li.ListTitle, div.ListTitle
	{mso-style-name:ListTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.FigureTitle, li.FigureTitle, div.FigureTitle
	{mso-style-name:FigureTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.TableTitle, li.TableTitle, div.TableTitle
	{mso-style-name:TableTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.ProgramTitle, li.ProgramTitle, div.ProgramTitle
	{mso-style-name:ProgramTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.RightText, li.RightText, div.RightText
	{mso-style-name:RightText;
	margin-top:0cm;
	margin-right:21.0pt;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	border:none;
	padding:0cm;
	font-size:9.0pt;
	font-family:宋体;}
p.af2, li.af2, div.af2
	{mso-style-name:表中文字小五;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:9.0pt;
	font-family:宋体;}
p.af3, li.af3, div.af3
	{mso-style-name:关键词;
	mso-style-link:"关键词 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char3
	{mso-style-name:"关键词 Char";
	mso-style-link:关键词;
	font-family:宋体;}
p.af4, li.af4, div.af4
	{mso-style-name:文件名;
	mso-style-link:"文件名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char4
	{mso-style-name:"文件名 Char";
	mso-style-link:文件名;
	font-family:宋体;}
p.af5, li.af5, div.af5
	{mso-style-name:选项;
	mso-style-link:"选项 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char5
	{mso-style-name:"选项 Char";
	mso-style-link:选项;
	font-family:宋体;}
p.af6, li.af6, div.af6
	{mso-style-name:命令行;
	mso-style-link:"命令行 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char6
	{mso-style-name:"命令行 Char";
	mso-style-link:命令行;
	font-family:宋体;}
p.af7, li.af7, div.af7
	{mso-style-name:函数名;
	mso-style-link:"函数名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char7
	{mso-style-name:"函数名 Char";
	mso-style-link:函数名;
	font-family:宋体;}
p.af8, li.af8, div.af8
	{mso-style-name:寄存器名;
	mso-style-link:"寄存器名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char8
	{mso-style-name:"寄存器名 Char";
	mso-style-link:寄存器名;
	font-family:"Times New Roman","serif";}
p.af9, li.af9, div.af9
	{mso-style-name:变量名;
	mso-style-link:"变量名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char9
	{mso-style-name:"变量名 Char";
	mso-style-link:变量名;
	font-family:宋体;}
p.58, li.58, div.58
	{mso-style-name:图中文字小5号左;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.59, li.59, div.59
	{mso-style-name:图中文字小5号靠左;
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.926, li.926, div.926
	{mso-style-name:"样式 代码程序 + 左侧\:  9\.26 厘米";
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:10.0pt;
	font-family:宋体;}
span.5Char4
	{mso-style-name:"标题 5 Char";
	mso-style-link:"标题 5";
	font-weight:bold;}
span.6Char0
	{mso-style-name:"标题 6 Char";
	mso-style-link:"标题 6";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.7Char
	{mso-style-name:"标题 7 Char";
	mso-style-link:"标题 7";
	font-weight:bold;}
span.8Char
	{mso-style-name:"标题 8 Char";
	mso-style-link:"标题 8";
	font-family:"Arial","sans-serif";}
span.9Char
	{mso-style-name:"标题 9 Char";
	mso-style-link:"标题 9";
	font-family:"Arial","sans-serif";}
span.Chara
	{mso-style-name:"脚注文本 Char";
	mso-style-link:脚注文本;
	font-family:宋体;}
span.Charb
	{mso-style-name:"批注文字 Char";
	mso-style-link:批注文字;
	font-family:宋体;}
span.Charc
	{mso-style-name:"页眉 Char";
	mso-style-link:页眉;
	font-family:宋体;}
span.Chard
	{mso-style-name:"页脚 Char";
	mso-style-link:页脚;
	font-family:宋体;}
span.Chare
	{mso-style-name:"日期 Char";
	mso-style-link:日期;
	font-family:宋体;}
span.HTMLChar
	{mso-style-name:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char";
	mso-style-link:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3";
	font-family:宋体;}
span.Charf
	{mso-style-name:"批注主题 Char";
	mso-style-link:批注主题;
	font-family:宋体;
	font-weight:bold;}
span.Charf0
	{mso-style-name:"批注框文本 Char";
	mso-style-link:批注框文本;
	font-family:宋体;}
span.3CharChar1
	{mso-style-name:"图中文字3 Char Char1";
	font-family:宋体;}
span.3CharChar3
	{mso-style-name:"图中文字3 Char Char3";
	font-family:宋体;}
.MsoChpDefault
	{font-size:10.0pt;}
 /* Page Definitions */
 @page WordSection1
	{size:595.3pt 841.9pt;
	margin:72.0pt 54.0pt 72.0pt 54.0pt;
	layout-grid:15.6pt;}
div.WordSection1
	{page:WordSection1;}
 /* List Definitions */
 ol
	{margin-bottom:0cm;}
ul
	{margin-bottom:0cm;}
-->
</style>

</head>

<body lang=ZH-CN link=blue vlink=purple style='text-justify-trim:punctuation'>

<div class=WordSection1 style='layout-grid:15.6pt'>

<p class=ab><a name="_Toc53320636"><span style='font-family:黑体'>程序</span><span
lang=EN-US>12-1 linux/fs/buffer.c</span></a></p>

<div class=a align=center style='text-align:center'><span lang=EN-US>

<hr size=4 width="100%" align=center>

</span></div>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>1</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>2</span></u> <b><i>&nbsp;*&nbsp;
linux/fs/buffer.c</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>3</span></u> <b><i>&nbsp;*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>4</span></u> <b><i>&nbsp;*&nbsp;
(C) 1991&nbsp; Linus Torvalds</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>5</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>6</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>7</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>8</span></u> <b><i>&nbsp;*&nbsp;
'buffer.c' implements the buffer-cache functions. Race-conditions have</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>9</span></u> <b><i>&nbsp;*
been avoided by NEVER letting a interrupt change a buffer (except for the</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>10</span></u> <b><i>&nbsp;*
data, of course), but instead letting the caller do it. NOTE! As interrupts</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>11</span></u> <b><i>&nbsp;*
can wake up a caller, some cli-sti sequences are needed to check for</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>12</span></u> <b><i>&nbsp;*
sleep-on-calls. These should be extremely quick, though (I hope).</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>13</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * 'buffer.c'</span>用于实现缓冲区高速缓存功能。通过不让中断处理过程改变缓冲区，而是让调</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>用者来执行，避免了竞争条件（当然除改变数据以外）。注意！由于中断可以唤醒一个调</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>用者，因此就需要开关中断指令（<span
lang=EN-US>cli-sti</span>）序列来检测由于调用而睡眠。但需要非常地快</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>（我希望是这样）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>14</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>15</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>16</span></u> <b><i>&nbsp;*
NOTE! There is one discordant note here: checking floppies for</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>17</span></u> <b><i>&nbsp;*
disk change. This is where it fits best, I think, as it should</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>18</span></u> <b><i>&nbsp;*
invalidate changed floppy-disk-caches.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>19</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>注意！有一个程序应不属于这里：检测软盘是否更换。但我想这里是放置</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>该程序最好的地方了，因为它需要使已更换软盘缓冲失效。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>20</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>21</span></u>
#include &lt;stdarg.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>标准参数头文件。以宏的形式定义变量参数列表。主要说明了<span
lang=EN-US>-</span>个</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>类型<span lang=EN-US>(va_list)</span>和三个宏<span lang=EN-US>(va_start,
va_arg</span>和<span lang=EN-US>va_end)</span>，用于</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// vsprintf</span>、<span lang=EN-US>vprintf</span>、<span lang=EN-US>vfprintf</span>函数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>22</span></u>&nbsp;
</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>23</span></u>
#include &lt;linux/config.h&gt; // </span>内核配置头文件。定义键盘语言和硬盘类型（<span lang=EN-US>HD_TYPE</span>）可选项。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>24</span></u>
#include &lt;linux/sched.h&gt;&nbsp; // </span>调度程序头文件，定义了任务结构<span lang=EN-US>task_struct</span>、任务<span
lang=EN-US>0</span>的数据，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>还有一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>25</span></u>
#include &lt;linux/kernel.h&gt; // </span>内核头文件。含有一些内核常用函数的原形定义。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>26</span></u> #include
&lt;asm/system.h&gt;&nbsp;&nbsp; // </span>系统头文件。定义了设置或修改描述符<span lang=EN-US>/</span>中断门等的嵌入汇编宏。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>27</span></u>
#include &lt;asm/io.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // io</span>头文件。定义硬件端口输入<span
lang=EN-US>/</span>输出宏汇编语句。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>28</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>变量<span lang=EN-US>end</span>是由编译时的连接程序<span
lang=EN-US>ld</span>生成，用于表明内核代码的末端，即指明内核模块末端</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>位置，参见<b>错误<span lang=EN-US>!</span>未找到引用源。</b>。也可以从编译内核时生成的 <span lang=EN-US>System.map</span>文件中查出。这里用它来表</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>明高速缓冲区开始于内核代码末端位置。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>第<span lang=EN-US>33</span>行上的<span
lang=EN-US>buffer_wait</span>变量是等待空闲缓冲块而睡眠的任务队列头指针。它与缓冲块头</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>部结构中<span lang=EN-US>b_wait</span>指针的作用不同。当任务申请一个缓冲块而正好遇到系统缺乏可用空闲缓</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>冲块时，当前任务就会被添加到<span
lang=EN-US>buffer_wait</span>睡眠等待队列中。而<span lang=EN-US>b_wait</span>则是专门供等待</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>指定缓冲块（即<span
lang=EN-US>b_wait</span>对应的缓冲块）的任务使用的等待队列头指针。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>29</span></u>
extern int <u><span style='color:blue'>end</span></u>;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>30</span></u>
struct <u><span style='color:blue'>buffer_head</span></u> * <u><span
style='color:blue'>start_buffer</span></u> = (struct <u><span style='color:
blue'>buffer_head</span></u> *) &amp;<u><span style='color:blue'>end</span></u>;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>31</span></u>
struct <u><span style='color:blue'>buffer_head</span></u> * <u><span
style='color:blue'>hash_table</span></u>[<u><span style='color:blue'>NR_HASH</span></u>];&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// NR_HASH = 307</span>项。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>32</span></u>
static struct <u><span style='color:blue'>buffer_head</span></u> * <u><span
style='color:blue'>free_list</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>空闲缓冲块链表头指针。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>33</span></u>
static struct <u><span style='color:blue'>task_struct</span></u> * <u><span
style='color:blue'>buffer_wait</span></u> = <u><span style='color:blue'>NULL</span></u>;&nbsp;
// </span>等待空闲缓冲块而睡眠的任务队列。</p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>下面定义系统缓冲区中含有的缓冲块个数。这里，<span
lang=EN-US>NR_BUFFERS</span>是一个定义在<span lang=EN-US>linux/fs.h</span>头</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>文件第<span lang=EN-US>48</span>行的宏，其值即是变量名<span
lang=EN-US>nr_buffers</span>，并且在<span lang=EN-US>fs.h</span>文件第<span
lang=EN-US>172</span>行声明为全局变量。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>大写名称通常都是一个宏名称，<span
lang=EN-US>Linus</span>这样编写代码是为了利用这个大写名称来隐含地表示</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // nr_buffers</span>是一个在内核初始化之后不再改变的“常量”。它将在初始化函数<span
lang=EN-US>buffer_init()</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>中被设置（第<span
lang=EN-US>371</span>行）。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>34</span></u> int
<u><span style='color:blue'>NR_BUFFERS</span></u> =
0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//
</span>系统含有缓冲块个数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>35</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>等待指定缓冲块解锁。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果指定的缓冲块<span
lang=EN-US>bh</span>已经上锁就让进程不可中断地睡眠在该缓冲块的等待队列<span lang=EN-US>b_wait</span>中。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在缓冲块解锁时，其等待队列上的所有进程将被唤醒。虽然是在关闭中断（<span
lang=EN-US>cli</span>）之后去睡</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>眠的，但这样做并不会影响在其他进程上下文中响应中断。因为每个进程都在自己的<span
lang=EN-US>TSS</span>段</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>中保存了标志寄存器<span
lang=EN-US>EFLAGS</span>的值，所以在进程切换时<span lang=EN-US>CPU</span>中当前<span
lang=EN-US>EFLAGS</span>的值也随之改变。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>使用<span lang=EN-US>sleep_on()</span>进入睡眠状态的进程需要用<span
lang=EN-US>wake_up()</span>明确地唤醒。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>36</span></u>
static inline void <u><span style='color:blue'>wait_on_buffer</span></u>(struct
<u><span style='color:blue'>buffer_head</span></u> * bh)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>37</span></u> {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>38</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>cli</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>关中断。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>39</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
while (bh-&gt;b_lock)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>如果已被上锁则进程进入睡眠，等待其解锁。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>40</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>sleep_on</span></u>(&amp;bh-&gt;b_wait);</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>41</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>sti</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>开中断。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>42</span></u> }</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>43</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>设备数据同步。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>同步设备和内存高速缓冲中数据。其中，<span
lang=EN-US>sync_inodes()</span>定义在<span lang=EN-US>inode.c</span>，<span
lang=EN-US>59</span>行。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>44</span></u> int
<u><span style='color:blue'>sys_sync</span></u>(void)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>45</span></u> {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>46</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
int i;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>47</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
struct <u><span style='color:blue'>buffer_head</span></u> * bh;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>48</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先调用<span lang=EN-US>i</span>节点同步函数，把内存<span
lang=EN-US>i</span>节点表中所有修改过的<span lang=EN-US>i</span>节点写入高速缓冲中。然后</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>扫描所有高速缓冲区，对已被修改的缓冲块产生写盘请求，将缓冲中数据写入盘中，做到</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>高速缓冲中的数据与设备中的同步。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>49</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>sync_inodes</span></u>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b><i>/*
write out inodes into buffers */</i></b> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>50</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh = <u><span style='color:blue'>start_buffer</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// bh</span>指向缓冲区开始处。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>51</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for (i=0 ; i&lt;<u><span style='color:blue'>NR_BUFFERS</span></u> ; i++,bh++) {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>52</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>wait_on_buffer</span></u>(bh);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>等待缓冲区解锁（如果已上锁的话）。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>53</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_dirt)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>54</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>ll_rw_block</span></u>(<u><span style='color:blue'>WRITE</span></u>,bh);&nbsp;&nbsp;
// </span>产生写设备块请求。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>55</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>56</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>57</span></u> }</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>58</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>对指定设备进行高速缓冲数据与设备上数据的同步操作。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数首先搜索高速缓冲区中所有缓冲块。对于指定设备<span
lang=EN-US>dev</span>的缓冲块，若其数据已被修改</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>过就写入盘中（同步操作）。然后把内存中<span
lang=EN-US>i</span>节点表数据写入高速缓冲中。之后再对指定设</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>备<span lang=EN-US>dev</span>执行一次与上述相同的写盘操作。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>59</span></u> int
<u><span style='color:blue'>sync_dev</span></u>(int dev)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>60</span></u> {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>61</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
int i;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>62</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
struct <u><span style='color:blue'>buffer_head</span></u> * bh;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>63</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先对参数指定的设备执行数据同步操作，让设备上的数据与高速缓冲区中的数据同步。</p>

<p class=a><span lang=EN-US>&nbsp; &nbsp;&nbsp;// </span>方法是扫描高速缓冲区中所有缓冲块，对指定设备<span
lang=EN-US>dev</span>的缓冲块，先检测其是否已被上锁，</p>

<p class=a><span lang=EN-US>&nbsp; &nbsp;&nbsp;// </span>若已被上锁就睡眠等待其解锁。然后再判断一次该缓冲块是否还是指定设备的缓冲块并且</p>

<p class=a><span lang=EN-US>&nbsp; &nbsp;&nbsp;// </span>已修改过（<span lang=EN-US>b_dirt</span>标志置位），若是就对其执行写盘操作。因为在我们睡眠期间该缓冲块</p>

<p class=a><span lang=EN-US>&nbsp; &nbsp;&nbsp;// </span>有可能已被释放或者被挪作它用，所以在继续执行前需要再次判断一下该缓冲块是否还是</p>

<p class=a><span lang=EN-US>&nbsp; &nbsp;&nbsp;// </span>指定设备的缓冲块，</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>64</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh = <u><span style='color:blue'>start_buffer</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// bh</span>指向缓冲区开始处。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>65</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for (i=0 ; i&lt;<u><span style='color:blue'>NR_BUFFERS</span></u> ; i++,bh++) {&nbsp;&nbsp;&nbsp;
</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>66</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_dev != dev)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>不是设备<span lang=EN-US>dev</span>的缓冲块则继续。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>67</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>68</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>wait_on_buffer</span></u>(bh);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>等待缓冲区解锁（如果已上锁的话）。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>69</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_dev == dev &amp;&amp; bh-&gt;b_dirt)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>70</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>ll_rw_block</span></u>(<u><span style='color:blue'>WRITE</span></u>,bh);</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>71</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>再将<span lang=EN-US>i</span>节点数据写入高速缓冲。让<span
lang=EN-US>i</span>节点表<span lang=EN-US style='color:#333333'>inode_table</span><span
style='color:#333333'>中的<span lang=EN-US>inode</span>与缓冲中的信息同步。</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>72</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>sync_inodes</span></u>();</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后在高速缓冲中的数据更新之后，再把它们与设备中的数据同步。这里采用两遍同步操作</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>是为了提高内核执行效率。第一遍缓冲区同步操作可以让内核中许多“脏块”变干净，使得</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // i</span>节点的同步操作能够高效执行。本次缓冲区同步操作则把那些由于<span
lang=EN-US>i</span>节点同步操作而又变</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>脏的缓冲块与设备中数据同步。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>73</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh = <u><span style='color:blue'>start_buffer</span></u>;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>74</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for (i=0 ; i&lt;<u><span style='color:blue'>NR_BUFFERS</span></u> ; i++,bh++) {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>75</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_dev != dev)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>76</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>77</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>wait_on_buffer</span></u>(bh);</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>78</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_dev == dev &amp;&amp; bh-&gt;b_dirt)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>79</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>ll_rw_block</span></u>(<u><span style='color:blue'>WRITE</span></u>,bh);</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>80</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>81</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>82</span></u> }</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>83</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>使指定设备在高速缓冲区中的数据无效。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>扫描高速缓冲区中所有缓冲块。对指定设备的缓冲块复位其有效<span
lang=EN-US>(</span>更新<span lang=EN-US>)</span>标志和已修改标志。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>84</span></u>
void inline <u><span style='color:blue'>invalidate_buffers</span></u>(int dev)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>85</span></u> {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>86</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
int i;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>87</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
struct <u><span style='color:blue'>buffer_head</span></u> * bh;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>88</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>89</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh = <u><span style='color:blue'>start_buffer</span></u>;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>90</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for (i=0 ; i&lt;<u><span style='color:blue'>NR_BUFFERS</span></u> ; i++,bh++) {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>91</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_dev !=
dev)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //
</span>如果不是指定设备的缓冲块，则</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>92</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>继续扫描下一块。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>93</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>wait_on_buffer</span></u>(bh);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>等待该缓冲区解锁（如果已被上锁）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>由于进程执行过睡眠等待，所以需要再判断一下缓冲区是否是指定设备的。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>94</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_dev == dev)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>95</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_uptodate = bh-&gt;b_dirt = 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>96</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>97</span></u> }</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>98</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>99</span></u> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>100</span></u><span
lang=EN-US> <b><i>&nbsp;* This routine checks whether a floppy has been
changed, and</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>101</span></u><span
lang=EN-US> <b><i>&nbsp;* invalidates all buffer-cache-entries in that case.
This</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>102</span></u><span
lang=EN-US> <b><i>&nbsp;* is a relatively slow routine, so we have to try to
minimize using</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>103</span></u><span
lang=EN-US> <b><i>&nbsp;* it. Thus it is called only upon a 'mount' or 'open'.
This</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>104</span></u><span
lang=EN-US> <b><i>&nbsp;* is the best way of combining speed and utility, I
think.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>105</span></u><span
lang=EN-US> <b><i>&nbsp;* People changing diskettes in the middle of an
operation deserve</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>106</span></u><span
lang=EN-US> <b><i>&nbsp;* to loose :-)</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>107</span></u><span
lang=EN-US> <b><i>&nbsp;*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>108</span></u><span
lang=EN-US> <b><i>&nbsp;* NOTE! Although currently this is only for floppies,
the idea is</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>109</span></u><span
lang=EN-US> <b><i>&nbsp;* that any additional removable block-device will use
this routine,</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>110</span></u><span
lang=EN-US> <b><i>&nbsp;* and that mount/open needn't know that
floppies/whatever are</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>111</span></u><span
lang=EN-US> <b><i>&nbsp;* special.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>112</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>该子程序检查一个软盘是否已被更换，如果已经更换就使高速缓冲中与该软驱</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>对应的所有缓冲区无效。该子程序相对来说较慢，所以我们要尽量少使用它。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>所以仅在执行<span
lang=EN-US>'mount'</span>或<span lang=EN-US>'open'</span>时才调用它。我想这是将速度和实用性相结合的</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>最好方法。若在操作过程中更换软盘，就会导致数据的丢失。这是咎由自取<span
lang=EN-US style='font-family:Wingdings'>J</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; *</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>注意！尽管目前该子程序仅用于软盘，以后任何可移动介质的块设备都将使用该</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>程序，<span
lang=EN-US>mount/open</span>操作不需要知道是软盘还是其他什么特殊介质。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>检查磁盘是否更换，如果已更换就使对应高速缓冲区无效。</p>

<p class=a><u><span lang=EN-US style='color:blue'>113</span></u><span
lang=EN-US> void <u><span style='color:blue'>check_disk_change</span></u>(int
dev)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>114</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>115</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>116</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先检测一下是不是软盘设备。因为现在仅支持软盘可移动介质。如果不是则退出。然后</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>测试软盘是否已更换，如果没有则退出。<span
lang=EN-US>floppy_change()</span>在<span lang=EN-US>blk_drv/floppy.c</span>第<span
lang=EN-US>139</span>行。</p>

<p class=a><u><span lang=EN-US style='color:blue'>117</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>MAJOR</span></u>(dev) != 2)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>118</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>119</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!<u><span
style='color:blue'>floppy_change</span></u>(dev &amp; 0x03))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>120</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>软盘已经更换，所以释放对应设备的<span
lang=EN-US>i</span>节点位图和逻辑块位图所占的高速缓冲区；并使该</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>设备的<span lang=EN-US>i</span>节点和数据块信息所占踞的高速缓冲块无效。</p>

<p class=a><u><span lang=EN-US style='color:blue'>121</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=0 ; i&lt;<u><span
style='color:blue'>NR_SUPER</span></u> ; i++)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>122</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (<u><span style='color:blue'>super_block</span></u>[i].s_dev == dev)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>123</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>put_super</span></u>(<u><span style='color:blue'>super_block</span></u>[i].s_dev);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>124</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>invalidate_inodes</span></u>(dev);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>125</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<u><span
style='color:blue'>invalidate_buffers</span></u>(dev);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>126</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>127</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>下面两行代码是<span
lang=EN-US>hash</span>（散列）函数定义和<span lang=EN-US>hash</span>表项的计算宏。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // hash</span>表的主要作用是减少查找比较元素所花费的时间。通过在元素的存储位置与关键字之间</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>建立一个对应关系（<span
lang=EN-US>hash</span>函数），我们就可以直接通过函数计算立刻查询到指定的元素。建</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>立<span lang=EN-US>hash</span>函数的指导条件主要是尽量确保散列到任何数组项的概率基本相等。建立函数的方法</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>有多种，这里<span
lang=EN-US>Linux 0.12</span>主要采用了关键字除留余数法。因为我们寻找的缓冲块有两个条件，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>即设备号<span lang=EN-US>dev</span>和缓冲块号<span
lang=EN-US>block</span>，因此设计的<span lang=EN-US>hash</span>函数肯定需要包含这两个关键值。这里两个</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>关键字的异或操作只是计算关键值的一种方法。再对关键值进行<span
lang=EN-US>MOD</span>运算就可以保证函数所计</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>算得到的值都处于函数数组项范围内。</p>

<p class=a><u><span lang=EN-US style='color:blue'>128</span></u><span
lang=EN-US> #define <u><span style='color:blue'>_hashfn</span></u>(dev,block)
(((unsigned)(dev^block))%<u><span style='color:blue'>NR_HASH</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>129</span></u><span
lang=EN-US> #define <u><span style='color:blue'>hash</span></u>(dev,block) <u><span
style='color:blue'>hash_table</span></u>[<u><span style='color:blue'>_hashfn</span></u>(dev,block)]</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>130</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>从<span lang=EN-US>hash</span>队列和空闲缓冲队列中移走缓冲块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // hash</span>队列是双向链表结构，空闲缓冲块队列是双向循环链表结构。</p>

<p class=a><u><span lang=EN-US style='color:blue'>131</span></u><span
lang=EN-US> static inline void <u><span style='color:blue'>remove_from_queues</span></u>(struct
<u><span style='color:blue'>buffer_head</span></u> * bh)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>132</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>133</span></u><span
lang=EN-US> <b><i>/* remove from hash-queue */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>从<span lang=EN-US>hash</span>队列中移除缓冲块<span
lang=EN-US> */</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>134</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bh-&gt;b_next)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>135</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_next-&gt;b_prev = bh-&gt;b_prev;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>136</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bh-&gt;b_prev)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>137</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_prev-&gt;b_next = bh-&gt;b_next;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果该缓冲区是该队列的头一个块，则让<span
lang=EN-US>hash</span>表的对应项指向本队列中的下一个缓冲区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>138</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>hash</span></u>(bh-&gt;b_dev,bh-&gt;b_blocknr) == bh)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>139</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<u><span
style='color:blue'>hash</span></u>(bh-&gt;b_dev,bh-&gt;b_blocknr) =
bh-&gt;b_next;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>140</span></u><span
lang=EN-US> <b><i>/* remove from free list */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>从空闲缓冲块表中移除缓冲块<span
lang=EN-US> */</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>141</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(!(bh-&gt;b_prev_free) || !(bh-&gt;b_next_free))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>142</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;Free block list
corrupted&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>143</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_prev_free-&gt;b_next_free = bh-&gt;b_next_free;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>144</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_next_free-&gt;b_prev_free = bh-&gt;b_prev_free;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果空闲链表头指向本缓冲区，则让其指向下一缓冲区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>145</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>free_list</span></u> == bh)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>146</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>free_list</span></u> = bh-&gt;b_next_free;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>147</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>148</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>将缓冲块插入空闲链表尾部，同时放入<span
lang=EN-US>hash</span>队列中。</p>

<p class=a><u><span lang=EN-US style='color:blue'>149</span></u><span
lang=EN-US> static inline void <u><span style='color:blue'>insert_into_queues</span></u>(struct
<u><span style='color:blue'>buffer_head</span></u> * bh)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>150</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>151</span></u><span
lang=EN-US> <b><i>/* put at end of free list */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>放在空闲链表末尾处<span
lang=EN-US> */</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>152</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bh-&gt;b_next_free
= <u><span style='color:blue'>free_list</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>153</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bh-&gt;b_prev_free
= <u><span style='color:blue'>free_list</span></u>-&gt;b_prev_free;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>154</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>free_list</span></u>-&gt;b_prev_free-&gt;b_next_free = bh;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>155</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>free_list</span></u>-&gt;b_prev_free = bh;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>156</span></u><span
lang=EN-US> <b><i>/* put the buffer in new hash-queue if it has a device */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>如果该缓冲块对应一个设备，则将其插入新<span
lang=EN-US>hash</span>队列中<span lang=EN-US> */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>请注意当<span lang=EN-US>hash</span>表某项第<span
lang=EN-US>1</span>次插入项时，<span lang=EN-US>hash()</span>计算值肯定为<span lang=EN-US>NULL</span>，因此此时第<span
lang=EN-US>161</span>行上</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>得到的<span lang=EN-US>bh-&gt;b_next</span>肯定是<span
lang=EN-US>NULL</span>，所以第<span lang=EN-US>163</span>行上应该在<span lang=EN-US>bh-&gt;b_next</span>不为<span
lang=EN-US>NULL</span>时才能给</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // b_prev</span>赋<span
lang=EN-US>bh</span>值。即第<span lang=EN-US>163</span>行前应该增加判断“<span lang=EN-US>if
(bh-&gt;b_next)</span>”。该错误到<span lang=EN-US>0.96</span>版后</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>才被纠正。</p>

<p class=a><u><span lang=EN-US style='color:blue'>157</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bh-&gt;b_prev = <u><span
style='color:blue'>NULL</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>158</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bh-&gt;b_next = <u><span
style='color:blue'>NULL</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>159</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!bh-&gt;b_dev)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>160</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>161</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bh-&gt;b_next = <u><span
style='color:blue'>hash</span></u>(bh-&gt;b_dev,bh-&gt;b_blocknr);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>162</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>hash</span></u>(bh-&gt;b_dev,bh-&gt;b_blocknr) = bh;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>163</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_next-&gt;b_prev = bh; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//
</span>此句前应添加“<span lang=EN-US>if (bh-&gt;b_next)</span>”判断。</p>

<p class=a><u><span lang=EN-US style='color:blue'>164</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>165</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>利用<span lang=EN-US>hash</span>表在高速缓冲中寻找给定设备和指定块号的缓冲区块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果找到则返回缓冲区块的指针，否则返回<span
lang=EN-US>NULL</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>166</span></u><span
lang=EN-US> static struct <u><span style='color:blue'>buffer_head</span></u> * <u><span
style='color:blue'>find_buffer</span></u>(int dev, int block)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>167</span></u><span
lang=EN-US>
{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>168</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct <u><span
style='color:blue'>buffer_head</span></u> * tmp;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>169</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>搜索<span lang=EN-US>hash</span>表，寻找指定设备号和块号的缓冲块。</p>

<p class=a><u><span lang=EN-US style='color:blue'>170</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (tmp = <u><span
style='color:blue'>hash</span></u>(dev,block) ; tmp != <u><span
style='color:blue'>NULL</span></u> ; tmp = tmp-&gt;b_next)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>171</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (tmp-&gt;b_dev==dev &amp;&amp; tmp-&gt;b_blocknr==block)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>172</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return tmp;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>173</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return <u><span
style='color:blue'>NULL</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>174</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>175</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>176</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>177</span></u><span
lang=EN-US> <b><i>&nbsp;* Why like this, I hear you say... The reason is
race-conditions.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>178</span></u><span
lang=EN-US> <b><i>&nbsp;* As we don't lock buffers (unless we are readint them,
that is),</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>179</span></u><span
lang=EN-US> <b><i>&nbsp;* something might happen to it while we sleep (ie a
read-error</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>180</span></u><span
lang=EN-US> <b><i>&nbsp;* will force it bad). This shouldn't really happen
currently, but</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>181</span></u><span
lang=EN-US> <b><i>&nbsp;* the code is ready.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>182</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>代码为什么会是这样子的？我听见你问<span
lang=EN-US>... </span>原因是竞争条件。由于我们没有对</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>缓冲块上锁（除非我们正在读取它们中的数据），那么当我们（进程）睡眠时</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>缓冲块可能会发生一些问题（例如一个读错误将导致该缓冲块出错）。目前</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>这种情况实际上是不会发生的，但处理的代码已经准备好了。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>利用<span lang=EN-US>hash</span>表在高速缓冲区中寻找指定的缓冲块。若找到则对该缓冲块上锁并返回块头指针。</p>

<p class=a><u><span lang=EN-US style='color:blue'>183</span></u><span
lang=EN-US> struct <u><span style='color:blue'>buffer_head</span></u> * <u><span
style='color:blue'>get_hash_table</span></u>(int dev, int block)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>184</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>185</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct <u><span
style='color:blue'>buffer_head</span></u> * bh;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>186</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>187</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (;;) {</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在高速缓冲中寻找给定设备和指定块的缓冲区块，如果没有找到则返回<span
lang=EN-US>NULL</span>，退出。</p>

<p class=a><u><span lang=EN-US style='color:blue'>188</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!(bh=<u><span style='color:blue'>find_buffer</span></u>(dev,block)))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>189</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return <u><span style='color:blue'>NULL</span></u>;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>对该缓冲块增加引用计数，并等待该缓冲块解锁（如果已被上锁）。由于经过了睡眠状态，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>因此有必要再验证该缓冲块的正确性，并返回缓冲块头指针。</p>

<p class=a><u><span lang=EN-US style='color:blue'>190</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_count++;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>191</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>wait_on_buffer</span></u>(bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>192</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_dev == dev &amp;&amp; bh-&gt;b_blocknr == block)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>193</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return bh;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果在睡眠时该缓冲块所属的设备号或块号发生了改变，则撤消对它的引用计数，重新寻找。</p>

<p class=a><u><span lang=EN-US style='color:blue'>194</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_count--;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>195</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>196</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>197</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>198</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>199</span></u><span
lang=EN-US> <b><i>&nbsp;* Ok, this is getblk, and it isn't very clear, again to
hinder</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>200</span></u><span
lang=EN-US> <b><i>&nbsp;* race-conditions. Most of the code is seldom used, (ie
repeating),</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>201</span></u><span
lang=EN-US> <b><i>&nbsp;* so it should be much more efficient than it looks.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>202</span></u><span
lang=EN-US> <b><i>&nbsp;*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>203</span></u><span
lang=EN-US> <b><i>&nbsp;* The algoritm is changed: hopefully better, and an
elusive bug removed.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>204</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * OK</span>，下面是<span
lang=EN-US>getblk</span>函数，该函数的逻辑并不是很清晰，同样也是因为要考虑</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>竞争条件问题。其中大部分代码很少用到，<span
lang=EN-US>(</span>例如重复操作语句<span lang=EN-US>)</span>，因此它应该</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>比看上去的样子有效得多。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; *</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>算法已经作了改变：希望能更好，而且一个难以琢磨的错误已经去除。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>下面宏用于同时判断缓冲区的修改标志和锁定标志，并且定义修改标志的权重要比锁定标志</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>大。</p>

<p class=a><u><span lang=EN-US style='color:blue'>205</span></u><span
lang=EN-US> #define <u><span style='color:blue'>BADNESS</span></u>(bh)
(((bh)-&gt;b_dirt&lt;&lt;1)+(bh)-&gt;b_lock)</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>取高速缓冲中指定的缓冲块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>检查指定（设备号和块号）的缓冲区是否已经在高速缓冲中。如果指定块已经在高速缓冲中，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则返回对应缓冲区头指针退出；如果不在，就需要在高速缓冲中设置一个对应设备号和块号的</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>新项。返回相应缓冲区头指针。</p>

<p class=a><u><span lang=EN-US style='color:blue'>206</span></u><span
lang=EN-US> struct <u><span style='color:blue'>buffer_head</span></u> * <u><span
style='color:blue'>getblk</span></u>(int dev,int block)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>207</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>208</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct <u><span
style='color:blue'>buffer_head</span></u> * tmp, * bh;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>209</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>210</span></u><span
lang=EN-US> repeat:</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>搜索<span lang=EN-US>hash</span>表，如果指定块已经在高速缓冲中，则返回对应缓冲区头指针，退出。</p>

<p class=a><u><span lang=EN-US style='color:blue'>211</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bh = <u><span
style='color:blue'>get_hash_table</span></u>(dev,block))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>212</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return bh;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>扫描空闲数据块链表，寻找空闲缓冲区。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先让<span lang=EN-US>tmp</span>指向空闲链表的第一个空闲缓冲区头。</p>

<p class=a><u><span lang=EN-US style='color:blue'>213</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp = <u><span
style='color:blue'>free_list</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>214</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果该缓冲区正被使用（引用计数不等于<span
lang=EN-US>0</span>），则继续扫描下一项。对于<span lang=EN-US>b_count=0</span>的块，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>即高速缓冲中当前没有引用的块不一定就是干净的（<span
lang=EN-US>b_dirt=0</span>）或没有锁定的（<span lang=EN-US>b_lock=0</span>）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>因此，我们还是需要继续下面的判断和选择。例如当一个任务改写过一块内容后就释放了，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>于是该块<span lang=EN-US>b_count
= 0</span>，但<span lang=EN-US>b_lock</span>不等于<span lang=EN-US>0</span>；当一个任务执行 <span
lang=EN-US>breada()</span>预读几个块时，只要</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // ll_rw_block()</span>命令发出后，它就会递减<span
lang=EN-US>b_count</span>；但此时实际上硬盘访问操作可能还在进行，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>因此此时<span lang=EN-US>b_lock=1</span>，但<span
lang=EN-US>b_count=0</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>215</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (tmp-&gt;b_count)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>216</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
continue;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果缓冲头指针<span
lang=EN-US>bh</span>为空，或者<span lang=EN-US>tmp</span>所指缓冲头的标志<span lang=EN-US>(</span>修改、锁定<span
lang=EN-US>)</span>权重小于<span lang=EN-US>bh</span>头标志的权</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>重，则让<span lang=EN-US>bh</span>指向<span
lang=EN-US>tmp</span>缓冲块头。 如果该<span lang=EN-US>tmp</span>缓冲块头表明缓冲块既没有修改也没有锁定标</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>志置位，则说明已为指定设备上的块取得对应的高速缓冲块，则退出循环。否则我们就继续</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>执行本循环，看看能否找到一个<span
lang=EN-US>BADNESS()</span>最小的缓冲快。</p>

<p class=a><u><span lang=EN-US style='color:blue'>217</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!bh || <u><span style='color:blue'>BADNESS</span></u>(tmp)&lt;<u><span
style='color:blue'>BADNESS</span></u>(bh)) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>218</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh = tmp;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>219</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!<u><span style='color:blue'>BADNESS</span></u>(tmp))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>220</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
break;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>221</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>222</span></u><span
lang=EN-US> <b><i>/* and repeat until we find something good */</i></b>&nbsp;
/* </span>重复操作直到找到适合的缓冲块<span lang=EN-US> */</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>223</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while ((tmp =
tmp-&gt;b_next_free) != <u><span style='color:blue'>free_list</span></u>);</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果循环检查发现所有缓冲块都正在被使用（所有缓冲块的头部引用计数都<span
lang=EN-US>&gt;0</span>）中，则睡眠</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>等待有空闲缓冲块可用。当有空闲缓冲块可用时本进程会被明确地唤醒。然后我们就跳转到</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>函数开始处重新查找空闲缓冲块。</p>

<p class=a><u><span lang=EN-US style='color:blue'>224</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!bh) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>225</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>sleep_on</span></u>(&amp;<u><span style='color:
blue'>buffer_wait</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>226</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto repeat;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>跳转至<span lang=EN-US>210</span>行。</p>

<p class=a><u><span lang=EN-US style='color:blue'>227</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>执行到这里，说明我们已经找到了一个比较适合的空闲缓冲块了。于是先等待该缓冲区解锁</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //</span>（如果已被上锁的话）。如果在我们睡眠阶段该缓冲区又被其他任务使用的话，只好重复上述</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>寻找过程。</p>

<p class=a><u><span lang=EN-US style='color:blue'>228</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>wait_on_buffer</span></u>(bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>229</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bh-&gt;b_count)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>又被占用？？</p>

<p class=a><u><span lang=EN-US style='color:blue'>230</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto repeat;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果该缓冲区已被修改，则将数据写盘，并再次等待缓冲区解锁。同样地，若该缓冲区又被</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>其他任务使用的话，只好再重复上述寻找过程。</p>

<p class=a><u><span lang=EN-US style='color:blue'>231</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while
(bh-&gt;b_dirt) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>232</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>sync_dev</span></u>(bh-&gt;b_dev);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>233</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>wait_on_buffer</span></u>(bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>234</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_count)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>又被占用？？</p>

<p class=a><u><span lang=EN-US style='color:blue'>235</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;goto repeat;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>236</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>237</span></u><span
lang=EN-US> <b><i>/* NOTE!! While we slept waiting for this block, somebody
else might */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>238</span></u><span
lang=EN-US> <b><i>/* already have added &quot;this&quot; block to the cache.
check it */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>注意！！当进程为了等待该缓冲块而睡眠时，其他进程可能已经将该缓冲块<span
lang=EN-US> */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>加入进高速缓冲中，所以我们也要对此进行检查。<span
lang=EN-US>*/</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在高速缓冲<span lang=EN-US>hash</span>表中检查指定设备和块的缓冲块是否乘我们睡眠之即已经被加入进去。如果</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>是的话，就再次重复上述寻找过程。</p>

<p class=a><u><span lang=EN-US style='color:blue'>239</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>find_buffer</span></u>(dev,block))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>240</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto repeat;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>241</span></u><span
lang=EN-US> <b><i>/* OK, FINALLY we know that this buffer is the only one of
it's kind, */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>242</span></u><span
lang=EN-US> <b><i>/* and that it's unused (b_count=0), unlocked (b_lock=0), and
clean */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* OK</span>，最终我们知道该缓冲块是指定参数的唯一一块，而且目前还没有被占用<span
lang=EN-US> */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* (b_count=0)</span>，也未被上锁<span
lang=EN-US>(b_lock=0)</span>，并且是干净的（未被修改的）<span lang=EN-US>*/</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>于是让我们占用此缓冲块。置引用计数为<span
lang=EN-US>1</span>，复位修改标志和有效<span lang=EN-US>(</span>更新<span lang=EN-US>)</span>标志。</p>

<p class=a><u><span lang=EN-US style='color:blue'>243</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bh-&gt;b_count=1;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>244</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bh-&gt;b_dirt=0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>245</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bh-&gt;b_uptodate=0;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>从<span lang=EN-US>hash</span>队列和空闲块链表中移出该缓冲区头，让该缓冲区用于指定设备和其上的指定块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后根据此新的设备号和块号重新插入空闲链表和<span
lang=EN-US>hash</span>队列新位置处。并最终返回缓冲</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>头指针。</p>

<p class=a><u><span lang=EN-US style='color:blue'>246</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>remove_from_queues</span></u>(bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>247</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bh-&gt;b_dev=dev;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>248</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_blocknr=block;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>249</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>insert_into_queues</span></u>(bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>250</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return bh;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>251</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>252</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>释放指定缓冲块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>等待该缓冲块解锁。然后引用计数递减<span
lang=EN-US>1</span>，并明确地唤醒等待空闲缓冲块的进程。</p>

<p class=a><u><span lang=EN-US style='color:blue'>253</span></u><span
lang=EN-US> void <u><span style='color:blue'>brelse</span></u>(struct <u><span
style='color:blue'>buffer_head</span></u> * <u><span style='color:blue'>buf</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>254</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>255</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!<u><span
style='color:blue'>buf</span></u>)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>如果缓冲头指针无效则返回。</p>

<p class=a><u><span lang=EN-US style='color:blue'>256</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>257</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>wait_on_buffer</span></u>(<u><span style='color:blue'>buf</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>258</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(<u><span
style='color:blue'>buf</span></u>-&gt;b_count--))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>259</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;Trying to free free
buffer&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>260</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>wake_up</span></u>(&amp;<u><span style='color:blue'>buffer_wait</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>261</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>262</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>263</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>264</span></u><span
lang=EN-US> <b><i>&nbsp;* bread() reads a specified block and returns the
buffer that contains</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>265</span></u><span
lang=EN-US> <b><i>&nbsp;* it. It returns NULL if the block was unreadable.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>266</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>从设备上读取指定的数据块并返回含有数据的缓冲区。如果指定的块不存在</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>则返回<span
lang=EN-US>NULL</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>从设备上读取数据块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数根据指定的设备号<span
lang=EN-US>dev</span>和数据块号<span lang=EN-US>block</span>，首先在高速缓冲区中申请一块缓冲块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果该缓冲块中已经包含有有效的数据就直接返回该缓冲块指针，否则就从设备中读取</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>指定的数据块到该缓冲块中并返回缓冲块指针。</p>

<p class=a><u><span lang=EN-US style='color:blue'>267</span></u><span
lang=EN-US> struct <u><span style='color:blue'>buffer_head</span></u> * <u><span
style='color:blue'>bread</span></u>(int dev,int block)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>268</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>269</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct <u><span
style='color:blue'>buffer_head</span></u> * bh;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>270</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在高速缓冲区中申请一块缓冲块。如果返回值是<span
lang=EN-US>NULL</span>，则表示内核出错，停机。然后我们</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>判断其中是否已有可用数据。 如果该缓冲块中数据是有效的（已更新的）可以直接使用，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则返回。</p>

<p class=a><u><span lang=EN-US style='color:blue'>271</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(bh=<u><span
style='color:blue'>getblk</span></u>(dev,block)))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>272</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;bread: getblk returned
NULL\n&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>273</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(bh-&gt;b_uptodate)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>274</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return bh;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>否则我们就调用底层块设备读写<span
lang=EN-US>ll_rw_block()</span>函数，产生读设备块请求。然后等待指定</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>数据块被读入，并等待缓冲区解锁。在睡眠醒来之后，如果该缓冲区已更新，则返回缓冲</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>区头指针，退出。否则表明读设备操作失败，于是释放该缓冲区，返回<span
lang=EN-US>NULL</span>，退出。</p>

<p class=a><u><span lang=EN-US style='color:blue'>275</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>ll_rw_block</span></u>(<u><span style='color:blue'>READ</span></u>,bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>276</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>wait_on_buffer</span></u>(bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>277</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(bh-&gt;b_uptodate)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>278</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return bh;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>279</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>brelse</span></u>(bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>280</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return <u><span
style='color:blue'>NULL</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>281</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>282</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>复制内存块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>从<span lang=EN-US>from</span>地址复制一块（<span
lang=EN-US>1024</span>字节）数据到<span lang=EN-US>to</span>位置。</p>

<p class=a><u><span lang=EN-US style='color:blue'>283</span></u><span
lang=EN-US> #define <u><span style='color:blue'>COPYBLK</span></u>(from,to) \</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>284</span></u><span
lang=EN-US> __asm__(<i>&quot;cld\n\t&quot;</i> \</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>285</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <i>&quot;rep\n\t&quot;</i>
\</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>286</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <i>&quot;movsl\n\t&quot;</i>
\</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>287</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::<i>&quot;c&quot;</i>
(<u><span style='color:blue'>BLOCK_SIZE</span></u>/4),<i>&quot;S&quot;</i>
(from),<i>&quot;D&quot;</i> (to) \</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>288</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :<i>&quot;cx&quot;</i>,<i>&quot;di&quot;</i>,<i>&quot;si&quot;</i>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>289</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>290</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>291</span></u><span
lang=EN-US> <b><i>&nbsp;* bread_page reads four buffers into memory at the
desired address. It's</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>292</span></u><span
lang=EN-US> <b><i>&nbsp;* a function of its own, as there is some speed to be
got by reading them</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>293</span></u><span
lang=EN-US> <b><i>&nbsp;* all at the same time, not waiting for one to be read,
and then another</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>294</span></u><span
lang=EN-US> <b><i>&nbsp;* etc.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>295</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * bread_page</span>一次读四个缓冲块数据读到内存指定的地址处。它是一个完整的函数，
</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>因为同时读取四块可以获得速度上的好处，不用等着读一块，再读一块了。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>读设备上一个页面（<span
lang=EN-US>4</span>个缓冲块）的内容到指定内存地址处。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数<span lang=EN-US>address</span>是保存页面数据的地址；<span
lang=EN-US>dev</span>是指定的设备号；<span lang=EN-US>b[4]</span>是含有<span lang=EN-US>4</span>个设备数据块号</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的数组。该函数仅用于<span
lang=EN-US>mm/memory.c</span>文件的<span lang=EN-US>do_no_page()</span>函数中（第<span
lang=EN-US>386</span>行）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>296</span></u><span
lang=EN-US> void <u><span style='color:blue'>bread_page</span></u>(unsigned
long address,int dev,int b[4])</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>297</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>298</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct <u><span
style='color:blue'>buffer_head</span></u> * bh[4];</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>299</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>300</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数循环执行<span
lang=EN-US>4</span>次，根据放在数组<span lang=EN-US>b[]</span>中的<span lang=EN-US>4</span>个块号从设备<span
lang=EN-US>dev</span>中读取一页内容放到指定</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>内存位置<span lang=EN-US>
address</span>处。 对于参数<span lang=EN-US>b[i]</span>给出的有效块号，函数首先从高速缓冲中取指定设备</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>和块号的缓冲块。如果缓冲块中数据无效（未更新）则产生读设备请求从设备上读取相应数</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>据块。对于<span lang=EN-US>b[i]</span>无效的块号则不用去理它了。因此本函数其实可以根据指定的<span
lang=EN-US>b[]</span>中的块号</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>随意读取<span lang=EN-US>1—4</span>个数据块。</p>

<p class=a><u><span lang=EN-US style='color:blue'>301</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=0 ; i&lt;4 ;
i++)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>302</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (b[i]) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>若块号有效。</p>

<p class=a><u><span lang=EN-US style='color:blue'>303</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh[i] = <u><span style='color:blue'>getblk</span></u>(dev,b[i]))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>304</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!bh[i]-&gt;b_uptodate)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>305</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>ll_rw_block</span></u>(<u><span style='color:blue'>READ</span></u>,bh[i]);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>306</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
} else</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>307</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh[i] = <u><span style='color:blue'>NULL</span></u>;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>随后将<span lang=EN-US>4</span>个缓冲块上的内容顺序复制到指定地址处。在进行复制（使用）缓冲块之前我们</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>先要睡眠等待缓冲块解锁（若被上锁的话）。另外，因为可能睡眠过了，所以我们还需要</p>

<p class=a><span lang=EN-US>&nbsp; &nbsp;&nbsp;// </span>在复制之前再检查一下缓冲块中的数据是否是有效的。复制完后我们还需要释放缓冲块。</p>

<p class=a><u><span lang=EN-US style='color:blue'>308</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=0 ; i&lt;4 ;
i++,address += <u><span style='color:blue'>BLOCK_SIZE</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>309</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh[i]) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>310</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>wait_on_buffer</span></u>(bh[i]);&nbsp;&nbsp; // </span>等待缓冲块解锁<span
lang=EN-US>(</span>若被上锁的话<span lang=EN-US>)</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>311</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh[i]-&gt;b_uptodate)&nbsp;&nbsp; // </span>若缓冲块中数据有效的话则复制。</p>

<p class=a><u><span lang=EN-US style='color:blue'>312</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>COPYBLK</span></u>((unsigned long)
bh[i]-&gt;b_data,address);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>313</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>brelse</span></u>(bh[i]);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>释放该缓冲区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>314</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>315</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>316</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>317</span></u><span
lang=EN-US> <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>318</span></u><span
lang=EN-US> <b><i>&nbsp;* Ok, breada can be used as bread, but additionally to
mark other</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>319</span></u><span
lang=EN-US> <b><i>&nbsp;* blocks for reading as well. End the argument list
with a negative</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>320</span></u><span
lang=EN-US> <b><i>&nbsp;* number.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>321</span></u><span
lang=EN-US> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * OK</span>，<span
lang=EN-US>breada</span>可以象<span lang=EN-US>bread</span>一样使用，但会另外预读一些块。该函数参数列表</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>需要使用一个负数来表明参数列表的结束。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>从指定设备读取指定的一些块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>函数参数个数可变，是一系列指定的块号。成功时返回第<span
lang=EN-US>1</span>块的缓冲块头指针，否则返回</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // NULL</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>322</span></u><span
lang=EN-US> struct <u><span style='color:blue'>buffer_head</span></u> * <u><span
style='color:blue'>breada</span></u>(int dev,int first, ...)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>323</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>324</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>va_list</span></u> args;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>325</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct <u><span
style='color:blue'>buffer_head</span></u> * bh, *tmp;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>326</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先取可变参数表中第<span
lang=EN-US>1</span>个参数（块号）。接着从高速缓冲区中取指定设备和块号的缓冲</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>块。如果该缓冲块数据无效（更新标志未置位），则发出读设备数据块请求。</p>

<p class=a><u><span lang=EN-US style='color:blue'>327</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>va_start</span></u>(args,first);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>328</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(bh=<u><span
style='color:blue'>getblk</span></u>(dev,first)))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>329</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;bread: getblk returned
NULL\n&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>330</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(!bh-&gt;b_uptodate)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>331</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>ll_rw_block</span></u>(<u><span style='color:blue'>READ</span></u>,bh);</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后顺序取可变参数表中其他预读块号，并作与上面同样处理，但不引用。注意，<span
lang=EN-US>336</span>行上</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>有一个<span lang=EN-US>bug</span>。其中的<span
lang=EN-US>bh</span>应该是<span lang=EN-US>tmp</span>。这个<span lang=EN-US>bug</span>直到在<span
lang=EN-US>0.96</span>版的内核代码中才被纠正过来。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>另外，因为这里是预读随后的数据块，只需读进高速缓冲区但并不马上就使用，所以第<span
lang=EN-US>337</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>行语句需要将其引用计数递减释放掉该块（因为<span
lang=EN-US>getblk()</span>函数会增加缓冲块引用计数值）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>332</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ((first=<u><span
style='color:blue'>va_arg</span></u>(args,int))&gt;=0) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>333</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
tmp=<u><span style='color:blue'>getblk</span></u>(dev,first);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>334</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (tmp) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>335</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!tmp-&gt;b_uptodate)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>336</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>ll_rw_block</span></u>(<u><span style='color:blue'>READA</span></u>,bh);&nbsp;&nbsp;&nbsp;
// bh </span>应该是<span lang=EN-US>tmp</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>337</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
tmp-&gt;b_count--;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>暂时释放掉该预读块。</p>

<p class=a><u><span lang=EN-US style='color:blue'>338</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>339</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>此时可变参数表中所有参数处理完毕。于是等待第<span
lang=EN-US>1</span>个缓冲区解锁（如果已被上锁）。在等</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>待退出之后如果缓冲区中数据仍然有效，则返回缓冲区头指针退出。否则释放该缓冲区返回</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // NULL</span>，退出。</p>

<p class=a><u><span lang=EN-US style='color:blue'>340</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>va_end</span></u>(args);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>341</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>wait_on_buffer</span></u>(bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>342</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(bh-&gt;b_uptodate)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>343</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return bh;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>344</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>brelse</span></u>(bh);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>345</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (<u><span
style='color:blue'>NULL</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>346</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>347</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>缓冲区初始化函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数<span lang=EN-US>buffer_end</span>是缓冲区内存末端。对于具有<span
lang=EN-US>16MB</span>内存的系统，缓冲区末端被设置为<span lang=EN-US>4MB</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>对于有<span lang=EN-US>8MB</span>内存的系统，缓冲区末端被设置为<span
lang=EN-US>2MB</span>。该函数从缓冲区开始位置<span lang=EN-US>start_buffer</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>处和缓冲区末端<span
lang=EN-US>buffer_end</span>处分别同时设置（初始化）缓冲块头结构和对应的数据块。直到</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>缓冲区中所有内存被分配完毕。参见程序列表前面的示意图。</p>

<p class=a><u><span lang=EN-US style='color:blue'>348</span></u><span
lang=EN-US> void <u><span style='color:blue'>buffer_init</span></u>(long
buffer_end)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>349</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>350</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct <u><span
style='color:blue'>buffer_head</span></u> * h = <u><span style='color:blue'>start_buffer</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>351</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void * b;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>352</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>353</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先根据参数提供的缓冲区高端位置确定实际缓冲区高端位置<span
lang=EN-US>b</span>。如果缓冲区高端等于<span lang=EN-US>1Mb</span>，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则因为从<span lang=EN-US>640KB
- 1MB</span>被显示内存和<span lang=EN-US> BIOS</span>占用，所以实际可用缓冲区内存高端位置应该是</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 640KB</span>。否则缓冲区内存高端一定大于<span
lang=EN-US>1MB</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>354</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (buffer_end ==
1&lt;&lt;20)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>355</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
b = (void *) (640*1024);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>356</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>357</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
b = (void *) buffer_end;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>这段代码用于初始化缓冲区，建立空闲缓冲块循环链表，并获取系统中缓冲块数目。操作的</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>过程是从缓冲区高端开始划分<span
lang=EN-US>1KB</span>大小的缓冲块，与此同时在缓冲区低端建立描述该缓冲块</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的结构<span lang=EN-US>buffer_head</span>，并将这些<span
lang=EN-US>buffer_head</span>组成双向链表。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // h</span>是指向缓冲头结构的指针，而<span
lang=EN-US>h+1</span>是指向内存地址连续的下一个缓冲头地址，也可以说是</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>指向<span lang=EN-US>h</span>缓冲头的末端外。为了保证有足够长度的内存来存储一个缓冲头结构，需要<span
lang=EN-US>b</span>所指向</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的内存块地址 <span
lang=EN-US>&gt;= h</span>缓冲头的末端，即要求 <span lang=EN-US>&gt;= h+1</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>358</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( (b -= <u><span
style='color:blue'>BLOCK_SIZE</span></u>) &gt;= ((void *) (h+1)) ) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>359</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_dev = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>使用该缓冲块的设备号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>360</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_dirt = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>脏标志，即缓冲块修改标志。</p>

<p class=a><u><span lang=EN-US style='color:blue'>361</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_count = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>缓冲块引用计数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>362</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_lock = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>缓冲块锁定标志。</p>

<p class=a><u><span lang=EN-US style='color:blue'>363</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_uptodate = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>缓冲块更新标志（或称数据有效标志）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>364</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_wait = <u><span style='color:blue'>NULL</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>指向等待该缓冲块解锁的进程。</p>

<p class=a><u><span lang=EN-US style='color:blue'>365</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_next = <u><span style='color:blue'>NULL</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>指向具有相同<span lang=EN-US>hash</span>值的下一个缓冲头。</p>

<p class=a><u><span lang=EN-US style='color:blue'>366</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_prev = <u><span style='color:blue'>NULL</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>指向具有相同<span lang=EN-US>hash</span>值的前一个缓冲头。</p>

<p class=a><u><span lang=EN-US style='color:blue'>367</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_data = (char *) b;&nbsp;&nbsp;&nbsp;&nbsp; // </span>指向对应缓冲块数据块（<span
lang=EN-US>1024</span>字节）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>368</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_prev_free = h-1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>指向链表中前一项。</p>

<p class=a><u><span lang=EN-US style='color:blue'>369</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h-&gt;b_next_free = h+1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>指向链表中下一项。</p>

<p class=a><u><span lang=EN-US style='color:blue'>370</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
h++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// h</span>指向下一新缓冲头位置。</p>

<p class=a><u><span lang=EN-US style='color:blue'>371</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>NR_BUFFERS</span></u>++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>缓冲区块数累加。</p>

<p class=a><u><span lang=EN-US style='color:blue'>372</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (b == (void *) 0x100000)&nbsp;&nbsp;&nbsp; // </span>若<span lang=EN-US>b</span>递减到等于<span
lang=EN-US>1MB</span>，则跳过<span lang=EN-US>384KB</span>，</p>

<p class=a><u><span lang=EN-US style='color:blue'>373</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
b = (void *) 0xA0000;&nbsp; // </span>让<span lang=EN-US>b</span>指向地址<span
lang=EN-US>0xA0000(640KB)</span>处。</p>

<p class=a><u><span lang=EN-US style='color:blue'>374</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>375</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; h--;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>让<span lang=EN-US>h</span>指向最后一个有效缓冲块头。</p>

<p class=a><u><span lang=EN-US style='color:blue'>376</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>free_list</span></u> = <u><span style='color:blue'>start_buffer</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>让空闲链表头指向头一个缓冲块。</p>

<p class=a><u><span lang=EN-US style='color:blue'>377</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>free_list</span></u>-&gt;b_prev_free = h;&nbsp; // </span>链表头的<span
lang=EN-US>b_prev_free</span>指向前一项（即最后一项）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>378</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; h-&gt;b_next_free =
<u><span style='color:blue'>free_list</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// h</span>的下一项指针指向第一项，形成一个环链。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>最后初始化<span lang=EN-US>hash</span>表（哈希表、散列表），置表中所有指针为<span
lang=EN-US>NULL</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>379</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=0;i&lt;<u><span
style='color:blue'>NR_HASH</span></u>;i++)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>380</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hash_table</span></u>[i]=<u><span style='color:
blue'>NULL</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>381</span></u><span
lang=EN-US> }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>382</span></u><span
lang=EN-US> </span></p>

<div class=a align=center style='text-align:center'><span lang=EN-US>

<hr size=4 width="100%" align=center>

</span></div>

<p class=MsoNormal><span lang=EN-US>&nbsp;</span></p>

<p class=MsoNormal><span lang=EN-US>&nbsp;</span></p>

</div>

</body>

</html>
